import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import ReportFormMachineOperationRecord from '@main/entities/service/admin/reportForm/report-form-period-status-monitoring.entity';
import { Repository, Between, In } from 'typeorm';
import BaseMachine from '@main/entities/service/admin/base/base-machine.entity';
import WipOrderReport from '@main/entities/service/admin/wip/wip-order-report.entity';
import ProductionOrder from '@main/entities/service/admin/production/production-order.entity';
import { ApiException } from '@main/common/exceptions/api.exception';
import { generateExcelFn } from '@main/excel';

@Injectable()
export class ReportFormMachineOperationRecordService {
  constructor(
    @InjectRepository(BaseMachine)
    private machineRepository: Repository<BaseMachine>,
    @InjectRepository(ReportFormMachineOperationRecord)
    private reportFormMachineOperationRecordRepository: Repository<ReportFormMachineOperationRecord>,
    @InjectRepository(WipOrderReport)
    private orderReportRepository: Repository<WipOrderReport>,
    @InjectRepository(ProductionOrder)
    private orderRepository: Repository<ProductionOrder>
  ) {}

  /**
   * 罗列所有配置
   */
  async page(data) {
    const { pageSize, pageNum, entity = {} } = data;

    const { machineCodeList, dateStartTime, dateEndTime, ids = [] } = entity;

    const whereObj = {};

    if (machineCodeList && machineCodeList.length > 0) {
      whereObj['machineCode'] = In(machineCodeList);
    }

    if (ids && ids.length) {
      whereObj['id'] = In(ids);
    }

    const [machineList, total]: any = await this.machineRepository.findAndCount({
      where: whereObj,
      order: {
        updateTime: 'DESC',
      },
      take: pageSize,
      skip: (pageNum - 1) * pageSize,
    });

    await Promise.all(
      machineList.map(async (item) => {
        const { machineCode } = item;

        const sTime = new Date(dateStartTime).getTime();

        const eTime = new Date(dateEndTime).getTime();

        const where: any = [
          {
            machineCode,
            startTime: Between(sTime, eTime),
          },
          {
            machineCode,
            endTime: Between(sTime, eTime),
          },
        ];

        const machineOperationRecordList =
          await this.reportFormMachineOperationRecordRepository.find({
            where,
            order: { updateTime: 'DESC' },
          });

        let dayDownCount = 0;

        let dayDownTime = 0;

        let dayRunTime = 0;

        for (const mItem of machineOperationRecordList) {
          const { machineStatus, startTime, endTime } = mItem;

          const nStartTime = new Date(startTime).getTime();

          const nEndTime = endTime ? new Date(endTime).getTime() : new Date().getTime();

          if (machineStatus === 0) {
            dayDownCount += 1;

            dayDownTime =
              dayDownTime +
              ((nEndTime > eTime ? eTime : nEndTime) - (nStartTime < sTime ? sTime : nStartTime)) /
                1000 /
                60 /
                60;
          } else if (machineStatus === 1) {
            const val =
              ((nEndTime > eTime ? eTime : nEndTime) - (nStartTime < sTime ? sTime : nStartTime)) /
              1000 /
              60 /
              60;

            dayRunTime += val;
          }
        }

        item['dayDownCount'] = dayDownCount;

        item['dayDownTime'] = dayDownTime.toFixed(2);

        item['dayRunTime'] = dayRunTime.toFixed(2);

        item['recordDate'] = dateStartTime.split(' ')[0];

        // let utRate = 0; // 稼动率（％）

        // let capRate = 0; // 性能效率（％）

        // let oeeRate = 0; // 设备OEE（％）

        // let quaRate = 0; // 合格率（％）

        // 2.5 稼动率 = 实际工作时间 / 计划工作时间，四舍五入保留2位小数；

        // 2.6 性能效率 = (合格数+缺陷数)*单件标准耗时 / 实际工作时间，单件标准耗时 = ∑ (计划调机用时+计划生产用时)/∑ 工单数量 ，合格数是指良品数，缺陷数是指不良品数，四舍五入保留2位小数；

        // 2.7 合格率 = 合格数/(合格数+缺陷数)，四舍五入保留2位小数；

        // 2.8 设备OEE = 稼动率 × 性能效率 × 合格率 ，四舍五入保留2位小数；

        const machineWorkOrderList = await this.orderReportRepository.find({
          where: {
            machineCode,
            reportStatus: 1,
            reportTime: Between(sTime as any, eTime),
          },
        });

        const machineWorkOrderList2 = [];

        for (const item of machineWorkOrderList) {
          const { reportTime, createTime, goodNum = 0, badNum = 0, orderCode } = item;

          const nCreateTime = new Date(createTime).getTime();

          const nReportTime = new Date(reportTime).getTime();

          const obj = machineWorkOrderList2.find((lItem) => lItem.orderCode === orderCode);

          if (!obj) {
            machineWorkOrderList2.push({
              orderCode,
              goodNum,
              badNum,
              productTime: nReportTime - nCreateTime,
            });
          } else {
            obj.goodNum += goodNum;

            obj.badNum += badNum;

            obj.productTime += nReportTime - nCreateTime;
          }
        }

        let allProductTime = 0;

        let allScheduledProductTime = 0;

        let allGoodNum = 0;

        let allBadNum = 0;

        let allScheduledDebugTime = 0;

        let allOrderNum = 0;

        await Promise.all(
          machineWorkOrderList2.map(async (mItem) => {
            const { orderCode, badNum, goodNum, productTime } = mItem;

            const obj2 = await this.orderRepository.findOne({
              where: {
                orderCode,
              },
            });

            if (obj2) {
              const { scheduledProductTime = 0, scheduledDebugTime = 0, orderNum } = obj2;

              allScheduledProductTime += scheduledProductTime;

              allScheduledDebugTime += scheduledDebugTime;

              allOrderNum += orderNum;
            }

            allProductTime += productTime;

            allGoodNum += goodNum;

            allBadNum += badNum;
          })
        );

        const utRate = (allProductTime / allScheduledProductTime) * 100;

        item['utRate'] = isNaN(utRate) ? '0.00' : utRate.toFixed(2);

        const capRate =
          ((allGoodNum + allBadNum) / ((allScheduledDebugTime + allProductTime) / allOrderNum)) *
          100;

        item['capRate'] = isNaN(capRate) ? '0.00' : capRate.toFixed(2);

        const quaRate = (allGoodNum / (allGoodNum + allBadNum)) * 100;

        item['quaRate'] = isNaN(quaRate) ? '0.00' : quaRate;

        let calUtRate = item['utRate'] === '0.00' ? 0 : item['utRate'] / 100;
        let calCapRate = item['capRate'] === '0.00' ? 0 : item['capRate'] / 100;
        let calQuaRate = item['quaRate'] === '0.00' ? 0 : item['quaRate'] / 100;
        item['oeeRate'] = (calUtRate * calCapRate * calQuaRate).toFixed(2);
      })
    );

    return [machineList, total];
  }

  async export(dto, lang) {
    const [list] = await this.page(dto);

    if (!list || !(list as any).length) {
      throw new ApiException(10052);
    }

    const dataList = list;

    return await generateExcelFn(
      {
        sheetName: 'machineOperationRecord',
        mainHeaderList: [
          {
            label: 'machineCode',
          },
          {
            label: 'machineName',
          },
          {
            label: 'dayRunTime',
          },
          {
            label: 'dayDownTime',
          },
          {
            label: 'dayDownCount',
          },
          {
            label: 'utRate',
          },
          {
            label: 'capRate',
          },
          {
            label: 'quaRate',
          },
          {
            label: 'oeeRate',
          },
          {
            label: 'recordDate',
          },
        ],
        dataList,
      },
      lang
    );
  }
}
